package com.shoulder.boot.ops.service.impl;

import com.jcraft.jsch.Session;
import com.shoulder.boot.ops.vo.SourceVo;
import com.shoulder.core.api.Kv;
import com.shoulder.ssh.properties.SSHProperties;
import com.shoulder.ssh.utils.ExecUtils;
import lombok.AllArgsConstructor;
import org.mockito.internal.matchers.Find;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shoulder.boot.ops.dto.MachineAddDTO;
import com.shoulder.boot.ops.utils.MachineUtils;
import com.shoulder.boot.ops.vo.MachineVo;
import com.shoulder.boot.ops.dto.MachineModDTO;
import com.shoulder.boot.ops.dto.MachineQueryDTO;
import com.shoulder.boot.ops.entity.Machine;
import com.shoulder.boot.ops.mapper.MachineMapper;
import com.shoulder.boot.ops.service.MachineService;
import com.shoulder.boot.ops.exception.OpsException;
import com.shoulder.core.fetch.BaseIds;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 机器信息 服务实现类
 *
 * @author unKnown
 * @since 2025-03-30 16:16:55
 */
@Service
@AllArgsConstructor
public class MachineServiceImpl extends ServiceImpl<MachineMapper, Machine> implements MachineService {

    private final SSHProperties sshProperties;

    @Override
    public List<MachineVo> listQuery(MachineQueryDTO queryDTO) {
        List<Machine> list = this.baseMapper.selectList(MachineUtils.buildQueryWrapper(queryDTO));
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return MachineUtils.buildUtils().toVos(list);
    }

    @Override
    public MachineVo look(String id) {
        Machine entity = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw new OpsException("机器信息不存在");
        }
        return MachineUtils.buildUtils().toVo(entity);
    }

    @Override
    public List<MachineVo> looks(BaseIds<String> baseIds) {
        List<Machine> list = this.baseMapper.selectBatchIds(baseIds.getIds());
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return MachineUtils.buildUtils().toVos(list);
    }

    @Override
    public void del(String id) {
        Machine entity = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw new OpsException("机器信息不存在");
        }
        this.baseMapper.deleteById(id);
    }

    @Override
    public void batchDel(BaseIds<String> baseIds) {
        this.baseMapper.deleteBatchIds(baseIds.getIds());
    }


    @Override
    public Page<MachineVo> pageQuery(MachineQueryDTO queryDTO) {
        Page<Machine> selectPage = this.baseMapper.selectPage(new Page<>(queryDTO.getCurrent(), queryDTO.getSize())
                , MachineUtils.buildQueryWrapper(queryDTO));
        if (selectPage == null || CollectionUtils.isEmpty(selectPage.getRecords())) {
            return new Page<>();
        }
        return MachineUtils.buildUtils().toPage(selectPage);
    }

    @Override
    public void mod(MachineModDTO modDTO) {
        Machine info = Optional.ofNullable(this.baseMapper.selectById(modDTO.getId())).orElseThrow(() -> new OpsException("机器信息不存在"));
        Machine machine = this.baseMapper.selectOne(new LambdaQueryWrapper<Machine>().eq(Machine::getHost, info.getHost())
                .eq(Machine::getPort, info.getPort()));
        if (!ObjectUtils.isEmpty(machine)) {
            throw new OpsException("已存在相同ip端口的机器");
        }
        BeanUtils.copyProperties(modDTO, info);
        this.baseMapper.updateById(info);
    }

    @Override
    public void add(MachineAddDTO addDTO) {
        Machine info = this.baseMapper.selectOne(new LambdaQueryWrapper<Machine>().eq(Machine::getHost, addDTO.getHost()).eq(Machine::getPort, addDTO.getPort()));
        if (!ObjectUtils.isEmpty(info)) {
            throw new OpsException("已存在同ip端口的机器");
        }
        info = new Machine();
        BeanUtils.copyProperties(addDTO, info);
        this.baseMapper.insert(info);
    }

    @Override
    public Machine noneScopeById(String id) {
        return this.baseMapper.noneScopeById(id);
    }

    @Override
    public SourceVo source(String id) throws Exception {
        Machine machine = this.baseMapper.selectById(id);
        if (ObjectUtils.isEmpty(machine)) {
            throw new OpsException("终端不存在");
        }
        //获取cpu信息
        ExecUtils execUtils = new ExecUtils();
        execUtils.setProperties(sshProperties);
        Session session = execUtils.init(machine.getHost(), machine.getUsername(), machine.getPassword());
        String cpu = "top -b -n1 | grep \"Cpu(s)\"";
        String cpuInfo = execUtils.execCmd(cpu, session);
        cpuInfo = cpuInfo.substring(8).trim();
        SourceVo vo = new SourceVo();
        for (String s : cpuInfo.split(",")) {
            String[] strings = s.trim().split(" ");
            String name = strings[1];
            if ("us".equals(name)) {
                vo.setUs(strings[0]);
            }
            if ("id".equals(name)) {
                vo.setId(strings[0]);
            }
            if ("sy".equals(name)) {
                vo.setSy(strings[0]);
            }
        }

        String mem = "free -m | awk 'NR==2{print $2,$3,$4}'";
        String memInfo = execUtils.execCmd(mem, session);
        memInfo= memInfo.replaceAll("\\s+", " ").trim().replace("\n","");

        String[] strings =memInfo.trim().split(" ");
        vo.setTm(new BigDecimal(strings[0]).divide(new BigDecimal(1024),2, RoundingMode.HALF_UP)+"GB");
        vo.setUm(new BigDecimal(strings[1]).divide(new BigDecimal(1024),2, RoundingMode.HALF_UP)+"GB");
        vo.setIm(new BigDecimal(strings[2]).divide(new BigDecimal(1024),2, RoundingMode.HALF_UP)+"GB");
        return vo;
    }
}